﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Collections;
using System.Threading;
using System.Data;
using log4net;
using System.Reflection;
using System.Configuration;
using System.IO;
using System.Xml;

namespace VipTest
{
    class Program
    {
        ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private List<Socket> lstConn;
        private List<Thread> lstThread;
        private List<string> lstEntrust219;
        private List<string> lstEntrust;
        private string strHost;
        private string strPort;
        private string strBranch;
        private string strCust;
        private string strPassword;
        private string strHolder_SH;
        private string strHolder_SZ;
        private string strHolder;
        private string strWTFS;
        private string strEntrustList;
        private string strMarket;
        private string strDate;
        private const int RECORD_NUM = 150;

        static void Main(string[] args)
        {
            Program p = new Program();
            p.lstConn = new List<Socket>();
            p.lstThread = new List<Thread>();
            p.lstEntrust = new List<string>();
            p.lstEntrust219 = new List<string>();

            if (!p.loadConfig())
            {
                p.log.Error("配置文件中HOST等关键信息缺失，请检查！");
                return;
            }

            if (!p.loadEntrust())
            {
                p.log.Error("读取委托列表文件失败，请检查！");
                return;
            }

            p.initConnection();
            p.executeQueryDate();
            p.showMainMenu();
        }

        private void showMainMenu()
        {
            bool bExit = false;
            string strMenu = "";
            StringBuilder sbMenu = new StringBuilder();
            sbMenu.Append("*******************************************************************\r\n");
            sbMenu.Append("Please choose command to execute:\r\n");
            sbMenu.Append("1. Execute the entrusts with Function 219\r\n");
            sbMenu.Append("2. Execute the entrusts with Function 3\r\n");
            sbMenu.Append("3. Query the Entrust status\r\n");
            sbMenu.Append("4. Query the RealDone status\r\n");
            sbMenu.Append("5. Query the RealDone status(Loop)\r\n");
            sbMenu.Append("6. Full process test\r\n");
            sbMenu.Append("0. Get following package\r\n");
            sbMenu.Append("c. Execute custom request\r\n");
            sbMenu.Append("X. Exit\r\n");
            sbMenu.Append("*******************************************************************");

            strMenu = sbMenu.ToString();

            while (!bExit)
            {
                Console.Out.WriteLine(strMenu);

            REINPUT:
                char cInput = Console.ReadKey(true).KeyChar;
                switch (cInput)
                {
                    case '1':
                        execute219();
                        break;
                    case '2':
                        execute3();
                        break;
                    case '3':
                        executeQueryEntrust();
                        break;
                    case '4':
                        executeQueryRealDone();
                        break;
                    case '5':
                        executeQueryRealDoneLoop();
                        break;
                    case '6':
                        execute219();
                        executeQueryRealDoneLoop();
                        break;
                    case '0':
                        executeGetFollowingPackage();
                        break;
                    case 'c':
                        executeCustomRequest();
                        break;
                    case 'X':
                        disconnect();
                        bExit = true;
                        break;
                    default:
                        goto REINPUT;
                }

            }
        }

        //private void executeEntrust()
        //{
        //    string hostIPString = "127.0.0.1";
        //    string hostPortString = "12990";
        //    IPEndPoint dateTimeHost;
        //    IPAddress hostIP = IPAddress.Parse(hostIPString);
        //    dateTimeHost = new IPEndPoint(hostIP, Int32.Parse(hostPortString));
        //    Socket conn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //    conn.Connect(dateTimeHost);
        //    int bytes = 0;
        //    string strRequest = "";
        //    strRequest = "R|||61|001|0||01066666|123456|WSWT||0|";
        //    //strRequest = "R|||22|001|WSWT|";
        //    //strRequest = "R|||1|001||0||01066666|WSWT||";
        //    byte[] byteArray = System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest);
        //    conn.Send(byteArray);
        //    Byte[] RecvBytes = new Byte[256];
        //    bytes = conn.Receive(RecvBytes, RecvBytes.Length, 0);
        //    string RecvString = System.Text.Encoding.GetEncoding("GB2312").GetString(RecvBytes, 0, bytes);
        //    Console.WriteLine(RecvString);
        //    //Console.ReadKey();

        //    strRequest = "R|||3|001|1||A123456789|600000|1|100|7.67|RJWT||||||||||||";
        //    byteArray = System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest);
        //    Console.WriteLine("Ready to send an entrust request. " + DateTime.Now.ToString("HH:mm:ss:fffff"));
        //    conn.Send(byteArray);
        //    RecvBytes = new Byte[256];
        //    bytes = conn.Receive(RecvBytes, RecvBytes.Length, 0);
        //    RecvString = System.Text.Encoding.GetEncoding("GB2312").GetString(RecvBytes, 0, bytes);
        //    Console.WriteLine("Got the answer. " + DateTime.Now.ToString("HH:mm:ss:fffff"));
        //    Console.WriteLine(RecvString);
        //    Console.ReadKey();

        //    conn.Shutdown(SocketShutdown.Both);
        //    conn.Close();
        //}

        private void initConnection()
        {
            IPEndPoint dateTimeHost;
            IPAddress hostIP = IPAddress.Parse(this.strHost);
            dateTimeHost = new IPEndPoint(hostIP, Int32.Parse(this.strPort));
            int bytes = 0;
            string strRequest = "R|||61|" + this.strBranch + "|0||" + this.strCust + "|" + this.strPassword + "|" + this.strWTFS + "||0|";
            byte[] byteRequest = System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest);
            Byte[] RecvBytes = new Byte[256];
            string RecvString = "";

            for (int i = 0; i < 11; i++)
            {
                Socket conn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                conn.Connect(dateTimeHost);
                conn.Send(byteRequest);
                bytes = conn.Receive(RecvBytes, RecvBytes.Length, 0);
                RecvString = System.Text.Encoding.GetEncoding("GB2312").GetString(RecvBytes, 0, bytes);
                Console.WriteLine(RecvString);
                this.lstConn.Add(conn);
            }
        }

        private void disconnect()
        {
            foreach (Socket conn in this.lstConn)
            {
                conn.Shutdown(SocketShutdown.Both);
                conn.Close();
            }
        }

        /// <summary>
        /// 多线程批量委托，每个请求15笔委托，10线程
        /// </summary>
        private void execute219()
        {
            this.lstThread.RemoveRange(0, this.lstThread.Count);
            GC.Collect();

            for (int i = 0; i < this.lstEntrust219.Count; i++)
            {
                Request req = new Request();
                req.conn = this.lstConn[i];
                req.byteRequest = System.Text.Encoding.GetEncoding("GB2312").GetBytes(lstEntrust219[i]);
                
                Thread t = new Thread(new ThreadStart(req.sendRequest));
                this.lstThread.Add(t);
            }

            foreach (Thread thread in this.lstThread)
            {
                thread.Start();
            }

        }

        /// <summary>
        /// 多线程普通委托，10线程，每线程顺序发送15笔委托
        /// </summary>
        private void execute3()
        {
            this.lstThread.RemoveRange(0, this.lstThread.Count);
            GC.Collect();

            int iTemp = 0;
            int iThread = 0;
            List<byte[]> lstRequest = new List<byte[]>();

            foreach (string strRequest in this.lstEntrust)
            { 
                lstRequest.Add(System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest));
                iTemp++;

                if (iTemp == 15)
                {
                    Request req = new Request();
                    req.conn = this.lstConn[iThread];
                    req.lstRequest = lstRequest;

                    Thread t = new Thread(new ThreadStart(req.sendRequests));
                    this.lstThread.Add(t);

                    iThread++;
                    iTemp = 0;
                    lstRequest = new List<byte[]>();
                }
            }

            foreach (Thread thread in this.lstThread)
            {
                thread.Start();
            }

        }

        private void testDBF()
        {

        }

        private bool loadConfig()
        {
            this.strHost = ConfigurationManager.AppSettings["HOST"].ToString();
            this.strPort = ConfigurationManager.AppSettings["PORT"].ToString();
            this.strBranch = ConfigurationManager.AppSettings["BRANCH"].ToString();
            this.strCust = ConfigurationManager.AppSettings["CUST"].ToString();
            this.strPassword = ConfigurationManager.AppSettings["PASSWORD"].ToString();
            this.strHolder_SH = ConfigurationManager.AppSettings["HOLDER_SH"].ToString();
            this.strHolder_SZ = ConfigurationManager.AppSettings["HOLDER_SZ"].ToString();
            this.strWTFS = ConfigurationManager.AppSettings["WTFS"].ToString();
            this.strEntrustList = ConfigurationManager.AppSettings["ENTRUST_LIST"].ToString();

            if (this.strHost == "" || this.strPort == "" || this.strBranch == "" || this.strCust == "" || this.strPassword == "" || this.strHolder_SH == "" || this.strHolder_SZ == "" || this.strWTFS == "" || this.strEntrustList == "")
            {
                log.Error("配置文件中HOST等关键信息缺失，请检查！");
                return false;
            }

            return true;
        }

        private bool loadEntrust()
        { 
            if (!File.Exists(strEntrustList))
            {
                return false;
            }

            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(this.strEntrustList);
                XmlNode root = xmlDoc.SelectSingleNode("Entrusts");
                XmlNodeList entrusts = root.ChildNodes;
                this.strMarket = root.Attributes["MARKET"].Value;
                string strEntrust = "";
                string strEntrust219 = "";
                int i = 0;

                if (this.strMarket == "1")
                {
                    this.strHolder = this.strHolder_SH;
                }
                else
                {
                    this.strHolder = this.strHolder_SZ;
                }

                foreach (XmlElement element in entrusts)
                {
                    strEntrust = "R|||3|" + this.strBranch + "|" + this.strMarket + "||" + strHolder + "|" +                    
                                element.GetAttribute("SEC_CODE") + "|" + "1" + "|" + element.GetAttribute("AMOUNT") + "|" + element.GetAttribute("PRICE") +
                                "|" + strWTFS + "||||||||||||";
                    this.lstEntrust.Add(strEntrust);

                    strEntrust219 += "1" + element.GetAttribute("SEC_CODE") + "," + element.GetAttribute("AMOUNT") + "," + element.GetAttribute("PRICE") + ";";
                    i++;

                    if (i == 15)
                    {
                        this.lstEntrust219.Add("R|||219|" + this.strBranch + "|" + this.strMarket + "||" + this.strCust + "|" + this.strHolder + "|0|" + strWTFS + "||15|" + strEntrust219 + "|");
                        strEntrust219 = "";
                        i = 0;
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.ToString());
                return false;
            }

            return true;
        }

        private void sendRequest(string strRequest)
        {
            Socket conn = this.lstConn[this.lstConn.Count - 1];
            Byte[] RecvBytes = new Byte[256];
            string RecvString = "";
            int bytes = 0;
            byte[] byteRequest = System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest);
            DateTime dtStart = DateTime.Now;
            conn.Send(byteRequest);
            bytes = conn.Receive(RecvBytes, RecvBytes.Length, 0);
            log.Info("Data Received. Used " + DateTime.Now.Subtract(dtStart).TotalMilliseconds.ToString() + "ms.");
            RecvString = System.Text.Encoding.GetEncoding("GB2312").GetString(RecvBytes, 0, bytes);
            log.Info(RecvString);
        }

        private string getResult(string strRequest)
        {
            Socket conn = this.lstConn[this.lstConn.Count - 1];
            Byte[] RecvBytes = new Byte[256];
            string RecvString = "";
            int bytes = 0;
            byte[] byteRequest = System.Text.Encoding.GetEncoding("GB2312").GetBytes(strRequest);
            //DateTime dtStart = DateTime.Now;
            conn.Send(byteRequest);
            bytes = conn.Receive(RecvBytes, RecvBytes.Length, 0);
            //log.Info("Data Received. Used " + DateTime.Now.Subtract(dtStart).TotalMilliseconds.ToString() + "ms.");
            RecvString = System.Text.Encoding.GetEncoding("GB2312").GetString(RecvBytes, 0, bytes);
            //log.Info(RecvString);
            return RecvString;
        }

        private void executeCustomRequest()
        {
            Console.Write("Request>");
            string strRequest = Console.ReadLine();
            sendRequest(strRequest);
        }

        private void executeQueryEntrust()
        {
            string strRequest = "R|||14|" + this.strBranch + "|" + this.strMarket + "||" + this.strCust + "|" + this.strDate + "|" + this.strDate + "|||" + RECORD_NUM + "|||" + this.strWTFS + "||1|1|||||" + strHolder_SZ + "|";
            sendRequest(strRequest);
        }

        private void executeQueryRealDone()
        {
            string strRequest = "R|||13|" + this.strBranch + "|" + this.strMarket + "||" + this.strCust + "|" + RECORD_NUM + "||||" + this.strWTFS + "|0|A||";
            sendRequest(strRequest);
        }

        private void executeQueryRealDoneLoop()
        {
            string strRequest = "R|||13|" + this.strBranch + "|" + this.strMarket + "||" + this.strCust + "|" + RECORD_NUM + "||||" + this.strWTFS + "|0|A||";
            string strResult = "";
            bool bStop = false;

            while (!bStop)
            {
                strResult = getResult(strRequest);
                if (!strResult.EndsWith("|0"))
                {
                    log.Info("Got RealDone.");
                    bStop = true;
                }
            }
        }

        private void executeQueryDate()
        {
            string strRequest = "R|||22|" + this.strBranch + "|" + this.strWTFS + "|";
            string strResult = getResult(strRequest);
            this.strDate = strResult.Substring(strResult.IndexOf("Y|") + 2, 8);
        }

        private void executeGetFollowingPackage()
        {
            string strRequest = "R|||0|" + this.strBranch + "|" + this.strWTFS + "|";
            sendRequest(strRequest);
        }
    }
}
